#include <xeroskernel.h>
#define MAXBUF 4
#define KBCONTROLPORT 0x64
#define KBREADPORT 0x60

char getkbchar(void);
int kbopen(void);

static char kbbuffer[MAXBUF];
static int kbtail;
static int kbhead;
static int kbdist;
static int readcnt;
static int req_length;
static void *ret_buffer;
static Bool echo;
static unsigned char eof_char;
static Bool eof_flag;

int kbopen() {
	//common keyboard initializer
	kbtail = 0;
	kbhead = 0;
	kbdist = 0;
	eof_char = (unsigned char)4;
	eof_flag = 0;
	enable_irq(1,0);
	return 0;
}
extern int kbdopen_echo(){
	//echoing keyboard initializer
	echo = 1;
	return kbopen();
}

extern int kbdopen_nonecho(){
	//non echoing keyboard initializer
	echo = 0;
	return kbopen();
}

extern int kbdclose(){
	enable_irq(1,1);
	return 0;
}

extern int kbdwrite(pcb *p, void *buffer, int buffer_len){
	//return -1 because we are not writing to keyboard
	return -1;
}

extern int kbdread(pcb *p, void *buffer, int buffer_len){
	//if eof_flag is toggled, dont read anything
	//otherwise set buffer parameters
	if(eof_flag) return 0;

	ret_buffer = buffer;
	req_length = buffer_len;
	readcnt = 0;
	return kbdflush();
}

extern int kbdioctl(pcb *p, unsigned long command, void *args){
	char inc;
	//change EOF only
	if( command  == 49 ) {
		// va_list ap;
		// ap = (va_list)args;
		// inc = va_list(ap, char ); //NEED TO PARSE ARGUMENTS
		eof_char = *((int *) args);
		return 0;
	}
	return -1;
}

extern int kbdflush(){
	//copies keyboard kernel buffer to application buffer
	//return number of bytes copied if '\n', EOF is encountered or desired buffer length is copied
	//returns negative otherwise (negative return value blocks process)
	while( readcnt < req_length ) {
		if( kbdist > 0) {
			int index = kbtail % MAXBUF;
			*((char *)ret_buffer + readcnt) = kbbuffer[index];
			char last_c = kbbuffer[index];
			++kbtail;
			++readcnt;
			--kbdist;
			if(last_c == '\n' || last_c == eof_char)
				break;
		}else{
			return -1;
		} 
	}
	
	return readcnt;
}

extern void fillbuffer() {
	//called everytime keyboard button is pressed
	//fills keyboard kernel buffer
	char c = getkbchar();
	if(kbdist < 4 && c != (char)0) {
		kbbuffer[kbhead % MAXBUF] = c;
		kbhead++;
		kbdist++;
	}
}

char getkbchar() {
	//read character from keyboard
	char inc;
	if(inb(KBCONTROLPORT) & 1){
		inc = inb( KBREADPORT );
		inc = kbtoa(inc);
		if(echo && inc != (char)0) kprintf("%c",inc);
		//if EOF detected
		if( inc == eof_char ) { //NEED TO INCLUDE CTRL-D
			kprintf(" EOF DETECTED \n");
			eof_flag = 1;
		}
		//kprintf("%c",inc); //DEBUG
		return inc;
	}
}
